Programmable Keyboard
Details
Abstract
Acknowledgements
B00125142 Violet Concordia
Author
Supervisor
Ivan Smyth
Declaration
FROM TEMPLATE
Introduction
Literature Review
Work Done Date
Theory
Testing
Discussion
Conclusions
Future Work
Project Schedule
Subtopic
Overview of the project and the background behind it.
Project objectives
Project challenges
Overview of the project space
Overview of similar projects
Overview of the component technologies
Technology Review
Functional Requirements
System Design
Implementation
Testing and Results
Acronyms Used
HID
USB
Human Interface Device
Universal Serial Bus
Description
This project is a physical, external USB HID Programmable through USB keyboard. It
is a broad use device that the user will define the purpose of by creating their own
program.
GUI Programmer
Two Way Serial Communication between the Programmer, and the MCU
Parsing/Exporting configurations From/To the JSON format, on both the Programmer,
and MCU sides
General usage overview
The keyboard will reduce a few seconds on every button tap. Time saved will build up
to minutes, hours, and days over an extended period of time.
Concept Drawings
Sketch
More Shading Sketch
Early GUI Concept
The MCU on board must be able to send and receive configuration data to the
plugged in PC
The MCU must act as an HID to the target device in order to behave as a keyboard
The MCU must be able to write and read the data on the EEPROM, so that the
configuration persists through a loss of power
MCU
Microcontroller Unit
Design
A case for the keyboard that houses the PCB and Buttons that is ergonomic and uses
the least amount of material to reduce waste and cost
A Programmer GUI Application written in C++, by use of Qt Creator that the user can
utilize to spec
Mechanical Buttons
USB-HID
Each key's actions will have customization for what actions the specific key will
perform on press, while holding the key down, and upon release of the key.
Motivation to design this device
Repetitive and straneous tasks will be reduced, and workflow rate increased, as the
keyboard will do exactly what it is programmed to do. It will not have the mistakes of
human input.
Programmer
MCU
MCU as HID
Primary user interface to design their experience
There is a wide variety of different Programmable keyboards
Pin assignment
An intuitive design for programming the keyboard
MCU
Data Processing
HID
Storage and access of the JSON configurations with the EEPROM
Interpreting the stored either in cache or EEPROM data as HID inputs, and sending
them to the target device
Wide variety of unconventional layouts. The purpose of the shape is usually
ergonomic
Usually intended as a separate keyboard alongside one for everyday typing
Pros and Cons
MCU
The keyboard will be fully standalone as it is an HID device. The device will see this
keyboard as a regular mouse/keyboard. This means that the keyboard will be usable
on any Operating System that uses the standard USB and HID protocols, including
Linux, Android, Windows, macOS, iOS, etc...
Switches
Switches come in a variety of different colors, that indicate their required force for
activation, and their sound levels
Yellow was chosen due to being fairly easy to press, and the relatively low sound level
compared to other switches.
Yellow is about the middle ground in required force and produced loudness
Common Colors
White is very quiet and produces minimal feedback
Blue requires relatively high force to press, and produces rather loud feedback
Software that is designed to interpret hardware human input to actions on a computer
Because there is software to interpret hardware readings, the software is what decides
the final inputs
IDE
Based on C++
Button Select area
Button Action area
Status Bar section for importing and exporting data
Sections
Action Type selection box
Action selection box
Navigation buttons
Move action up
Move action down
Remove action
Add selected action button
A casual user may do something as simple as binding the keys to characters they use
often.
An advanced user may use this device to speed up code development by writing out a
template of a method/letter/introduction/etc with a single keypress, or assisting in
execution of a specific sequence of keypresses and clicks.
Onboard software that communicates with the programmer and EEPROM in order to
store and read the stored data on the EEPROM, and link up the information with
specified keys, executing them as the keys are pressed.
Strain and frequency of strain on the fingers will also be reduced by reduction of the
distance required for the fingers to move, as a single keypress only requires one
finger, without any additional fingers to reach another finger, unlike a multi-key action.
The button layout and actions for the buttons must be clear and easy to understand
and use
Types
Standard keyboard layout
Special layout
Stenography is a popular unique layout that allows for incredible typing speeds for
short words (300 or more words per minute is achievable)
It is a standard for most commercial use keyboards to be flashable into any software
the user chooses
Examples of everyday USB-HID devices
A keyboard
A mouse
The user must be able to give different parameters for each button
MCU
Different MCUs were compared to each other, and the Arduino Pro micro was chosen
for this project
Software
Custom software
Standard software
Supports flashing to other firmwares
Full hardware and software access as the software is written for the specifications,
and not for a pre-determined format
Can be extended to support helper software that would extend the functionality of the
keyboard
Examples
Run terminal commands
Open/Close/Maximize/etc apps
Hook into other apps, including web apps
Cost Analysis
C++ was for development of the application
Qt Creator is a cross-platform IDE, concentrating on the developer’s experience to
provide an intuitive and powerful work environment for GUI development
IDE
Integrated Development Environment
Physical Dimensions
Pin Count
Mega has far more pins than the project could ever require.
Uno is on the lower side of usable pins.
Pro Micro has just enough pins.
Mega is simply too large.
Uno is an improvement, but still large.
Pro Micro is the perfect size.
TUD
Technological University Dublin
I am very grateful to Technological University Dublin for accepting me as a student,
and providing me with the opportunity to take on this project
I’d like to acknowledge and express my gratitude towards my project
supervisors, Ivan Smyth – who has taken on me and my custom project and has
provided excellent guidance and feedback throughout the development of this project.
I am also very grateful for the existence and availability of search
engines, the primarily used for this project being Google. It is a valuable resource for
research, even though you should not take every search result at face value, and
ensure at least a few other sources agree with the findings.
I would also like to thank my wonderful old and new friends and peers
that I was able to meet thanks to my ability to attend the awesome TUD
Blanchardstown Campus, and the quiet spaces provided for us to further our
education with minimal interruptions.
I’d like to offer my sincere apology and thanks to anyone else I may
have missed that has contributed to this project in any way.
This report illustrates the development of my 3rd year’s Project. The report hopes to
successfully portray an accurate thought process and workflow of this project, in full
detail, while giving credit where credit is due, and thoroughly explaining the choices
made during the development of this project. The report has been organised into
sections that each cover a wide topic, with table of contents to aid in smooth
navigation of the contents. The project aims to develop an everyday utility tool for
those that work with computers often, and hopes to improve their workflow, and ease
the stress on their fingers, while providing full control of the experience to the user, by
offering to the user to reprogram their device, using an intuitive GUI programmer.
Libraries used
Keyboard.h
Mouse.h
https://www.arduino.cc/reference/en/language/functions/usb/keyboard/
https://www.arduino.cc/reference/en/language/functions/usb/mouse/
Allows the microprocessor to send Mouse and Keyboard inputs to a device through
the USB
Button Detection
The buttons are connected in an array
For each row and column, the row is supplied with high signal, and the column is
checked for a high signal
If a high signal is found, that indicates that the button checked is pressed in
Diagram
Each box represents an individual button
Qt Creator was chosen because it operates in C++, which allows for a very low access
to Serial and Hardware. It is also efficient when compared to higher level languages,
which is always a positive
Debounce
Each of the buttons will have a dedicated boolean to check their debounce that is
stored inside of an array of booleans of button count length
Debounce is achieved through software
Ergonomics
Even though the hardware can support up to 256 buttons with the components
currently onboard, that would be far too many keys for comfort. The design is focused
on minimalism, comfort and quick familiarity with the keyboard to reduce memorization
required
The Shift Register is constantly shifting controls for the Multiplexers
The Columns multiplexer always supplies a high signal to one column at a time
The Rows multiplexer checks for a high signal
Allows easy conversion from char/byte and sending Keyboard input through the USB
connection
Allows sending mouse inputs through the USB connection
Keyboard
Serial Communication
Settings
Baud Rate
115200
Mode
Read/Write
Data Bits
8
Parity
No Parity
Stop Bits
One stop bit
Flow Control
No flow control
Elements
Button Selection
The user can select which button is being programmed by clicking on the button
When a button is selected, the data contained within the button is displayed on the
button actions box
Buttons action box
This box is responsible for determining what actions the button will perform
The current button's index is displayed at the top left
Category and Action selection
Categories
Press 'p'
Hold 'h'
Release 'r'
The action that will be executed upon pressing the button
The action that will keep on repeating while the button is pressed in
The action that will be executed upon release of the button
Actions
Key 'k'
Write 'w'
Click 'c'
Move Mouse 'm'
Presses a key x times
Value 'v'
ENTER
SHIFT
INSERT
Examples
Times 'x'
Examples
10
25
1
Delay in ms 'd'
Examples
25
Default 0
Default 1
Delay in ms 'd'
Examples
25
Default 0
Writes the text
Clicks
Value 'v'
Examples
0 (Left Click)
1 (Right Click)
2 (Middle Click)
Default 0
Times 'x'
Delay in ms 'd'
Examples
10
25
1
Examples
25
Default 0
Default 1
Moves the mouse relatively from it's current position
X goal 'x'
Examples
40
Y goal 'y'
Examples
30
Duration in ms 'd'
Examples
25
Default 0
The items in quotation marks next to the keywords are the encoded representations of
the keyword which are the actual values used inside the json in order to minimize the
data required during transmission and storage of the json
Key Up|Release 'ku'
Release a key
Value 'v'
ENTER
SHIFT
INSERT
Examples
Key Down 'kd'
Press down a key
Value 'v'
ENTER
SHIFT
INSERT
Examples
Button Actions List
Display of actions of the currently selected button
Displayed above configuration will write Hello World, write "Button is held in..." every
250ms while held in, and write "Button was released!" when the button is released.
Allows further customization of the action's properties via mouse click for selection,
and keyboard input for modification
Entries may be expanded and compacted via the arrows on the left side
Entries are indexed on the right side for convenience
Every second line has a different color for extra readibility
Right side buttons provide control over the currently selected action
The arrow keys provide reordering of the action
The minus sign provides an option to remove the action
Communication Buttons
Send empty buttons checkmark
Enabled
Will send all the buttons. Non-configured entries will wipe the potentially existing data
for that button
Disabled
Will skip non-configured entries
Write button
Checks if there is a Serial Port available
Sends the buttons data if a Serial Port is available
Displays a warning if the Serial Port is not available
Menu Bar
File
Import
Export
Clear
The programmer saves data when closed to a backup file, and checks if a backup file
exists and loads it if it does on launch using the import and export features that will be
mentioned below in the Menu Bar
Reads in a JSON structured file as runtime button configurations
Writes the button configurations JSON structured data to a file
Clears all the current button configurations
View
Opens up a console display that allows the user to monitor what the programmer is
doing, and what the Serial Port is saying
The baud rate was increased from the default 9600 bits per second to 115.2 kilobits
per second for faster data transfer
The MCU gives feedback to the Programmer, which also requires Read
Write is required for the Programmer to be able to send data to the MCU
Button Detection Approaches
Grid
For 4x6 buttons, 4+6=10 pins would be required. While those pins are available, 10
pins is rather heavy compared to other approaches
Multiplexed Grid
For 4x6 buttons, log2(4) + log2(6) buttons would be required (each log2() rounded up).
2 pins for the rows, and 3 for the columns, giving a total of 5
This approach cuts down the required pins to a half of the 10 with the Grid method
Multiplexed by Shift Register Grid
This approach is the most comples and requires the same 5 pins as Multiplexed Grid,
but instead, they are all output by a Shift Register. This cuts down the required pins to
3, 1 for data, and 2 for shifting. This approach was chosen for this project.
Case Design
3D Printing
Construction
A case can be built from many types of materials including Wood, Plastic, Metal, etc...
Held together by bolts and screws. This approach is not very permament because
there is room for last minute changes
A case can be designed using software, and printed by using a 3D printer that prints
physical objects by melting filament into shape.
For Example: If midway through the building of the case it was realised that a hole will
in fact have to be bigger than it is at the moment, this hole can be expanded, without
interfering with components that will depend on the hole, as they can also be adjusted
while constructing the case.
In most cases, when a design flaw is detected, the entire part has to be reprinted.
JSON
Reading and Writing
EEPROM
Method List
Shift Register
3 Pins
SER | B4
RCLK | D4
SRCLK | E1
Latch Pin
Register Clock
Shift Register Clock
Positive Edge Trigger
Positive Edge Trigger
RCLK is set low while new inputs are shifted in
Each time it goes from Low to High, a new input is shifted in
The input value that gets shifted in
EEPROM
2 Pins
Both pins dedicated for I2C communication
SCL | D0
SDA | D1
Button Input Probe
Requires Analog
1 Pin
B2
Reads the output of the Rows Multiplexer
A boolean array of button count length determines if the button was pressed in on the
previous cycle
If it was, do not process it again until it is unpressed
Methods
Schematic and PCB
Pro Micro rough sketch for clearance
Properties
boardWidth
17.78mm
boardLength
34.9mm
holeGap
2.54mm
holeDiameter
1.523mm
holeOffsetLeft
1.27mm
holeOffsetBottom
1.24mm
bodyHeight
2.2mm
pinHeightTop
3mm
pinHeightBottom
2mm
Sketch
USB C Clearance
Board
Legs
Base Sketch
Contacts Sketch
2.2mm body extrusion
3mm top and 2mm bottom contacts extrusion
Top
No Fill
Bottom
No Fill
+5V Fill
Ground Fill
Schematic
Custom Footprints
Custom Symbols
PCB
Pro Micro
34.9mm long
17.780mm wide
Multiplexer
Pro Micro
Shift Register
The 3D printed case
Design
Top Piece
Base Measurements
Basic Extrusion
Bottom part snap-ins
Fillet
Top layer suppports
Supports were added to compensate for the lost thickness for the buttons to be able to
snap in
The top extrusion is precisely 1.55mm for the buttons to go through and snap in, which
is lower than the 2mm used for every other surface
Extrusions to snap into the walls of the bottom piece
0.5mm Fillet to make prevent rough, uncomfortable edges, and give a nice look at the
same time
Buttons are 14x14mm
Spacing between buttons is 6mm
Wall width is 3mm
Bottom Piece
Base Measurements
Values used in the design
rows
4
cols
6
outskirt
6mm
support_gap
1.75mm
button_gap
6mm
button_size
14mm
full_button_size
button_gap + button_size
button_outskirt
6mm
walls_thickness
3mm
top_thickness
1.55mm
top_to_support_bottom
walls_thickness+top_thickness
support_buttom_to_button_clearance
7.8mm-top_to_support_bottom
text_depth
0.5mm
top_wall_height
5mm
bottom_wall_height
16mm
inside_height
top_wall_height + bottom_wall_height
outside_height
inside_height + walls_thickness*2
fillet
1mm
inner_wall_width
outskirt*2 + cols*(button_size+button_gap) - button_gap
outer_wall_width
inner_wall_width + walls_thickness*2
inner_wall_length
outskirt*2 + rows*(button_size+button_gap) - button_gap
outer_wall_length
inner_wall_length + walls_thickness*2
PCB_width
70.104mm
PCB_length
59.436mm
PCB_thiccness
1.6mm
PCB_holder_corner_length
5mm
PM_offset_left
30.226mm
PM_offset_top
2.640mm
PM_width
17.780mm
PM_length
34.798mm
vias_diameter
1.523mm
vias_gap
2.540mm
vias_offset_horizontal
1.270mm
vias_offset_vertical
1.240mm
USB_cable_diameter
3.75mm
USB_slot_angle
60 degrees
slot_in_depth
2mm
Initials on the bottom
The walls extrude 16mm high
Slot on the front for the cable to come through
The teeth that hold the piece in place
Cable Holder Piece
Base Measurements
Slots for the bottom piece to snap into
PCB Holder
Base Measurements
Extruded
Assembly
Outside View
Button
Midsection down clearance boundaries of the button
Dimensions
The button slots in 4.55mm deep
The button extends 3.25mm further cylindrically
Generic standard sized clearance of the button
Cable snap in
Individually
Snapped In
Cross Section from side
PCB and PCB Holder
Top and Bottom pieces
Cross Section from side
Individually
Snapped In
Individually
Snapped In
Production
3D Printer
Slicer
Material
Settings
Make
Volume
Version
Temperature
PLA (Silk)
2.4.1
Name
PrusaSlicer
0.28mm layer height
No brim (Skirt only)
60mm/s printing speed
0.2mm initial layer
20mm/s first layer speed
Type
Name
Silk Copper PLA
200 to 230C
Original Prusa i3 MK3S+ (kit)
25×21×21cm (x, y, z)
0.05 - 0.35 mm
Layer height
Nozzle
0.4mm
Hardened steel
Filament diameter
1.75 mm
Type
Diameter
Max travel speed
200+ mm/s
Extruder
Direct Drive, Bondtech gears, E3D V6 hotend
Print surface
Removable magnetic steel sheet (textured powder coated)
Bed Z-height adjustment
Prusa's SuperPINDA (7x7 reference points x4 samples each)
No supports or other additional settings
Top Piece
Duration
Print info
Slicer Preview
Total Duration
2:19 Hours
Total Filament
26.03 Grams
Bottom and Cable Holder Pieces
Duration
Slicer Preview
Total Duration
4:33 Hours
Total Filament
59.43 Grams
GUI
PCB
JSON
PC
I2C
SCL
SDA
RCLK
EEPROM
Settings
Properties
Grid
0.254mm
Track Width
1.25mm
Clearance
0.2mm
Via
Size
1mm
Hole
0.8mm
Design
Production
PCB Thickness
1.6mm
Layers
2
Graphical User Interface
Printed Circuit Board
JavaScript Object Notation
Personal Computer
I²C
Description
A communications protocol that supports multiple controllers and targets. It was
designed in 1982.
Properties
Packet Switched
Single Ended
Bitrate
0.1, 0.4, 1.0, 3.4, or 5.0 Megabits per second, depending on mode.
Protocol
Serial
Half-Duplex
Synchronous
Often referred to a Windows running machine, but in this project, it refers to a any
personal use computer that runs any common Operating System such as Linux,
Windows, Android, iOS, macOS, etc.
An open standard file format that uses human readable text to store and transfer data
objects made of attribute to value pairs and arrays
A board that has very precise conductive tracks leading to contacts that eventually
lead to either a via, or a hole that is part of an electronic component's footprint, which
is soldered to form a contact. Widely used in production as it is a fast, versatile and
relatively cheap way to connect many components with high precision
A visual form of user interface that the user can interact with, usually by either use of a
keyboard and/or mouse, or a touch input. The interface reacts to the input live and is
often used to control some application in a convenient fashion.
A multi-feature application that usually combines at least a source code editor, build
automation, and a debugger. Modern IDEs include a far wider variety of tools such as
error identification, formatting, color coding, refactoring, etc...
A small computer chip that contains one or more CPUs, memory, and input/output
peripherals.
CPU
Central Processing Unit
A processor that executes simply instructions at a very high rate.
A very common, industry standard specification for cables, connectors, power supply,
and protocols for connection between computers that can utilize every common type
of communication between any device that implements USB, such as a phone, a desk
computer, a laptop, a microcontroller, etc.
Ireland's first technological university, established on 1st of January, 2019. This project
was designed and implemented during attendance in this university.
A device that is intended to interpret human input of buttons or other means of
interaction, and translating it to computer input. The human part is not directly linked to
the output, which allows for further translation of the input, which is utilized in this
project.
Serial Clock Line
A line that is required to implement I2C communications. Handles timing
Serial Data Line
A line that is required to implement I2C communications. Handles data
Storage Register Clock
Used for clocking a Shift Register's input to the output
Electrically Erasable, Programmable, Read-Only Memory
A component capable of being read/written to/from electrical signals. In this case,
using the I2C protocol. EEPROM persists the stored data when it is unpowered.
Version
6.2.2
GCC 10.3.1 20210422
Red Hat 10.3.1-1
64 Bit
Python could've also been use as Qt has Python binds, but C++ was chosen due to
preference
Programming Languages
Programmer
Keyboard
Qt Creator
Available Choices
C++
Python
Pros
Cons
Pros
Cons
Low-level language
Offers high level of control over the system
Precise
It will do exactly what it is told
Requires high skill
C++ is an advanced language with many pitfalls, such as pointers
Efficient
While this project does not require high efficiency, C++ is a very efficient language
thanks to the fact that is is low-level.
Easy to make mistakes
Very easy to write something wrong and have a difficult time finding out what went
wrong, especially at lower familiarity of the language
Quick to develop
Confusing to debug - not having types makes it diffcult to properly debug something
without very manual investigating
Loosely typed language
Very easy to switch between object types
Loosely typed language
An often issue with a loosely typed language is not knowing what type a variable is,
which may cause unexpected issues
Simple, loose syntax
Inefficient compared to lower level languages
As mentioned previously, efficiency is not a big concern for this project, but it is worth
mentioning
SparkFun Pro Micro
Available Choices
C/C++
Micro Python
C++ was chosen due to familiarity and personal preference
C++ was chosen due to familiarity and personal preference and for the sake of
consistency between the Programmer and Keyboard
The pros and cons are the exact same as for the Programmer, as both options are
almost identical. Python and Micro Python are very similar in their nature, and C++
was already evaluated above
C++
A low-level cross-platform general purpose object-oriented programming language
that was created by Bjarne Stroustrup in 1985 as an extension to the C programming
language, or C with Classes.
Description
Properties
Strongly typed
Enforces strict restrictions when mixing different data types
Efficient
Not only is C++ a low-level language which offers high levels of optimization on it's
own, it was also designed with efficiency in mind.
12th of March, 2022
3rd of April, 2022
A finished, functioning physical device
Theory, Programmer, Schematic and PCB finished
Programmer
The programmer is able to achieve a stable communication with the Keyboard, writing
every button in sequence without fail for the total duration of testing
Buttons
The simple debounce code has proven to work perfectly at an insignificant cost of
processing/memory
All the buttons are able to process, even if they are all pressed in at the same time. In
the scenario of multiple buttons being pressed in, every button will be processed in
sequence. No overlap
Every button is fully responsive and programmable
HID
The HID inputs go through to the target device as expected
Tested on multiple (5+) devices, smooth operation on each. Including secure
computers, such as the one found on Campus. This is expected, as the keyboard is
seen as a mouse/keyboard
The project is an overall a success, with a few bumps along the way
Time constraints
The project was planned during the start of the year, which made it difficult to predict
the upcoming workload of the other modules
The layouts that would be found on everyday use keyboards
QWERTY
Dvorak
The flashed software determines the functionality of the keyboard
The LEDs are purely optional, and were not chosen for this project, reducing the price
by 20%, down to 24 Eur.
This makes the keyboard far more versatile, at the cost of requiring considerably more
expensive components.
While this is a more permament approach, it is also much quicker and precise than
constructing a case manually.
3D printing is achieved by slicing a 3D model with your specified parameters into
gcode, which is instructions for a 3D printer to replicate the 3D model as close as
possible, given the printers' physical and software capabilities.
High level language
Difficult to access hardware directly
Achieved by the help of the open-source ArduinoJson library
Communication to the chip was achieved by the help of the open-source Wire (I2C)
library
ArduinoJson.h
Wire.h
https://www.arduino.cc/reference/en/libraries/arduinojson/
https://www.arduino.cc/en/reference/wire
Provides tools for encoding, parsing and manipulation of JSON objects
Provides easy communication with multiple devices that use the I2C protocol for
communication
Libraries used
Native Qt Creator libraries
Github
https://github.com/Harmonised7/programmable_keyboard
IDE
CLion
Qt Creator
Build
#CL-213.6461.75
License
Education
Runtime version
11.0.13+7-b1751.21 amd64
Runtime
Java Virtual Machine
OpenJDK 64-Bit VM by JetBrains
Description
Description
CLion is a cross-platform IDE that is specifically designed for C and C++ code
development
Plugins used
PlatformIO
Web page
https://www.jetbrains.com/clion/
Web page
https://platformio.org/
Description
A collaborative platform for embedded development
Supports over 1000 different boards
The bridge between C/C++ code from CLion IDE, to the code written on your board
Web page
https://www.qt.io/
QMap
QList
QString
QJsonObject
QJsonArray
etc... (Refer to the github link to see every library used in this project)
QTimer
No external libraries were used
Project Settings
Based on CMake
CMake is an extensive open-source system that is used to manage the build process
on an operating system
First released in 2000
Developers
Andy Cedilnik
Bill Hoffman
Brad King
Ken Martin
Alexander Neundorf
The PCB connections to the multiplexer were slightly mixed up. This was fixed by a
simple remap array that translates the read in index into the real index of the button
Things I would approach differently if I were to design this project again
Because every experienced issue was related to hardware, I would focus less on my
preferred field (Software), and give more time and attention to hardware.
I am proud to know that I've kept a constant progression on my project which is
reflected on the github page.
I would not have bothered with the Arduino IDE at all, as I have found CLion to be far
preferable and enjoyable to work with.
The cable is replaceable for both cosmetics and in case of malfunction of the cable
Final product
Top View
Side View
Diagonal View
Inside View
Cable Entrance
Cable Exit
Top piece back side
18th of April, 2022
Draft Report
Created With
MindMaster